package com.daqsoft.service.project;

import com.daqsoft.dao.project.TaskDao;
import com.daqsoft.data.User;
import com.daqsoft.data.project.*;
import com.daqsoft.dto.StatusEnum;
import com.daqsoft.dto.TaskTypeEnum;
import com.daqsoft.service.system.UserManageService;
import com.daqsoft.util.DateUtil;
import com.daqsoft.util.Log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 任务服务层
 *
 * @author 周麟东 on 11:52
 */
@Service
public class TaskService {
    private Logger log = LoggerFactory.getLogger(getClass());
    @Autowired
    private TaskDao taskDao;
    @Autowired
    private UserManageService userService;
    @Autowired
    private NodeService nodeService;
    @Autowired
    private AttachmentService attachmentService;

    /**
     * 通过ID获取一个任务
     *
     * @param id 任务ID
     * @return 任务对象
     */
    public Task get(int id) {
        return taskDao.findOne(id);
    }

    /**
     * 保存一个任务
     *
     * @param verifierId 审核人userId
     * @param node       所属节点
     * @param task       任务对象
     * @return 返回已经保存的任务对象
     */
    public Task save(int verifierId, Node node, Task task, int pid, TaskTypeEnum taskTypeEnum) {
        //检查这个任务时间是否正确
        User verifier = userService.findOne(verifierId);
        task.setVerifier(verifier);
        task.setNode(node);
        Task pTask = taskDao.findOne(pid);
        task.setpTask(pTask);
        task.setProject(node.getProject());
        task.setType(taskTypeEnum);
        //保存任务
        task = taskDao.save(task);
        return task;
    }

    /**
     * 通过节点ID返回任务列表
     *
     * @param nodeId 节点ID
     * @return 任务对象集合
     */
    public List<Task> getTaskByNode(int nodeId) {
        Node node = nodeService.get(nodeId);
        //去除正在变更的和隐藏的
        return node.getTasks().stream().filter(t -> t.getStatus() != StatusEnum.HIDDEN && t.getStatus() != StatusEnum.CHANGING && t.getStatus() != StatusEnum.HIDDEN_CAN_CHANGE).collect(Collectors.toList());
    }

    /**
     * 通过父级ID查找任务
     *
     * @param pid 父级ID
     * @return 任务列表
     */
    public List<Task> getTaskByPid(int pid) {
        Task task = taskDao.findOne(pid);
        return task.getChildren();
    }

    @Transactional
    public boolean remove(int taskId) {
        //删除文件
        List<Attachment> list = attachmentService.getAttByTaskId(taskId);
        if (list != null) {
            for (Attachment attachment : list) {
                attachmentService.delete(attachment);
            }
        }
        //删除任务
        taskDao.delete(taskId);
        return true;
    }


    public Task save(Task task) {
        return taskDao.save(task);
    }

    /**
     * 通过审核人查找正在进行的任务
     *
     * @param user   审核人
     * @param isLeaf 是否为叶子任务
     * @return 任务集合
     */
    public List<Task> getTaskByVerifier(User user, boolean isLeaf) {
        List<Task> tasks = taskDao.findTaskByVerifier(user);
        tasks = tasks.stream().filter(t -> t.getStatus() != StatusEnum.HIDDEN && t.getStatus() != StatusEnum.CHANGING && t.getStatus() != StatusEnum.HIDDEN_CAN_CHANGE && t.getStatus() != StatusEnum.CHANGED).collect(Collectors.toList());
        return isLeaf ? simple(tasks) : tasks;
    }

    /**
     * 通过负责人查找正在进行的任务
     *
     * @param user   负责人对象
     * @param isLeaf 是否为叶子任务
     * @return 任务对象集合
     */
    public List<Task> getTaskByPrincipal(User user, boolean isLeaf) {
        List<Task> tasks = taskDao.findTaskByPrincipal(user);
        tasks = tasks.stream().filter(t -> t.getStatus() != StatusEnum.HIDDEN && t.getStatus() != StatusEnum.CHANGING && t.getStatus() != StatusEnum.HIDDEN_CAN_CHANGE && t.getStatus() != StatusEnum.CHANGED).collect(Collectors.toList());
        return isLeaf ? simple(tasks) : tasks;
    }

    /**
     * 通过项目查找正在进行任务
     *
     * @param project 项目
     * @param isLeaf  是否为叶子任务
     * @return 任务集合
     */
    public List<Task> getByProject(Project project, boolean isLeaf) {
        List<Task> tasks = taskDao.findByProject(project);
        tasks = tasks.stream().filter(t -> t.getStatus() != StatusEnum.HIDDEN && t.getStatus() != StatusEnum.CHANGING && t.getStatus() != StatusEnum.HIDDEN_CAN_CHANGE && t.getStatus() != StatusEnum.CHANGED).collect(Collectors.toList());
        return isLeaf ? simple(tasks) : tasks;
    }

    /**
     * 筛选出根任务 , 把父级集合全部删除掉
     *
     * @param tasks 任务集合
     * @return 任务集合
     */
    private List<Task> simple(List<Task> tasks) {
        if (tasks == null) {
            return null;
        }
        List<Task> taskList = new ArrayList<>();
        for (Task task : tasks) {
            if (task.getChildren() == null || task.getChildren().isEmpty()) {
                taskList.add(task);
            } else {
                List<Task> children = simple(task.getChildren());
                taskList.addAll(children);
            }
        }

        return taskList;
    }

    public void saveAll(List<Task> tasks) {
        taskDao.save(tasks);
    }

    /**
     * 每分钟检查一次任务是否到开启时间 , 如果到了就设置为未开启
     */
    @Scheduled(fixedRate = 1000 * 10)
    public void check() {
        List<Task> tasks = taskDao.findTaskByStatus(StatusEnum.WAIT);
        if (tasks == null || tasks.isEmpty()) {
            return;
        }
        Iterator<Task> iterator = tasks.iterator();
        while (iterator.hasNext()) {
            Task task = iterator.next();
            //如果节点未在进行中则删除
            if (task.getNode() != null && task.getNode().getStatus() != StatusEnum.PROCESS) {
                iterator.remove();
                continue;
            }
            task.setStatus(StatusEnum.UNOPEN);
        }
        if (tasks.isEmpty()) {
            return;
        }
        taskDao.save(tasks);
        log.info("任务查完成 , 共{}个节点设置为进行中", tasks.size());
    }

    /**
     * 将任务拷贝到另一个项目
     *
     * @param data   要拷贝的元素数据
     * @param node   这些数据被拷贝到哪个节点下
     * @param father 这些数据被拷贝到哪个父级节点下
     * @return 返回拷贝完成后的对象
     */
    @Transactional
    public List<Task> copyTask(List<Task> data, Node node, Task father) {
        if (node == null) {
            return null;
        }
        if (data == null) {
            return null;
        }
        List<Task> newTasks = new ArrayList<>();
        for (Task task : data) { //保存任务
            Task newTask = cloneTask(task);
            newTask.setProject(node.getProject());
            newTask.setNode(node);
            if (father != null) { // 如果父级不为空
                newTask.setpTask(father);
            }
            if (task.getAttachments() != null) { // 如果附件不为空 , 那么就拷贝附件
                newTask.setAttachments(attachmentService.copyAttachments(task.getAttachments(), newTask));
            }
            if (task.getChildren() != null) {
                newTask.setChildren(copyTask(task.getChildren(), node, newTask));
            }
            newTask = taskDao.save(newTask);
            newTasks.add(newTask);
        }
        return newTasks;

    }

    /**
     * 克隆任务 不是单纯的克隆 有一定的修改:
     * id设置为0
     * Project为空 不设置
     * Node为空 不设置
     * attachments 附件列表不设置 为空
     *
     * @param task 需要被克隆的对象
     * @return 新建的对象
     */
    private Task cloneTask(Task task) {
        Task newTask = new Task();
        newTask.setName(task.getName());
        newTask.setDesc(task.getDesc());
        newTask.setQuestion(task.getQuestion());
        newTask.setSolution(task.getSolution());
        newTask.setPrincipal(task.getPrincipal());
        newTask.setVerifier(task.getVerifier());
        newTask.setType(task.getType());
        newTask.setStatus(task.getStatus());
        newTask.setStartDate(task.getStartDate());
        newTask.setEndDate(task.getEndDate());
        newTask.setRealStartDate(task.getRealStartDate());
        newTask.setRealEndDate(task.getRealEndDate());
        return newTask;
    }

    /**
     * 更改正在执行的任务状态
     *
     * @param task       任务对象
     * @param verifier   责任人对象
     * @param principal  负责人对象
     * @param statusEnum 状态
     * @return 修改后任务对象
     */
    public Task updateChangeTask(Task task, User verifier, User principal, StatusEnum statusEnum) {

        task.setVerifier(verifier);
        task.setPrincipal(principal);
        task.setStatus(statusEnum);
        task.setMsg("变更任务:变更任务状态 -->" + statusEnum.name());
        //变更任务的父级任务是否完成
        Task father = task.getpTask();
        if (father != null) {
            if (statusEnum == StatusEnum.FINISH) {
                boolean isFinish = true;
                for (Task children : father.getChildren()) {
                    if (children.getStatus() != StatusEnum.FINISH) {
                        isFinish = false;
                        break;
                    }
                }
                if (isFinish) {
                    father.setStatus(StatusEnum.FINISH);
                }
            }
            if (statusEnum == StatusEnum.PROCESS || statusEnum == StatusEnum.ERROR || statusEnum == StatusEnum.CHECK || statusEnum == StatusEnum.CHECKED || statusEnum == StatusEnum.UNOPEN) {
                father.setStatus(StatusEnum.PROCESS);
            }
            taskDao.save(father);
        } else { // 如果父级为空则说明需要判断节点是否已经可以完成
            Node node = task.getNode();
            if (statusEnum == StatusEnum.FINISH) {
                boolean isFinish = true;
                for (Task children : node.getTasks()) {
                    if (children.getStatus() != StatusEnum.FINISH) {
                        isFinish = false;
                        break;
                    }
                }
                if (isFinish) {
                    node.setStatus(StatusEnum.FINISH);
                }
            }
            if (statusEnum == StatusEnum.PROCESS || statusEnum == StatusEnum.ERROR || statusEnum == StatusEnum.CHECK || statusEnum == StatusEnum.CHECKED || statusEnum == StatusEnum.UNOPEN) {
                node.setStatus(StatusEnum.PROCESS);
            }
            nodeService.save(node);
        }
        //查看儿子任务是否全部完成
        if (task.getChildren() != null && statusEnum == StatusEnum.FINISH) {
            for (Task children : task.getChildren()) {
                updateChangeTask(children, children.getVerifier(), children.getPrincipal(), StatusEnum.FINISH);
            }
        }
        taskDao.save(task);
        return task;
    }


    /**
     * 暂停任务
     *
     * @param task    任务
     * @param isPause 是否暂停 是为true 不是为false
     * @return 任务对象
     */
    public Task pauseTask(Task task, boolean isPause) {

        //先暂停自己
        task.setPause(isPause);
        task = taskDao.save(task);
        //暂停自己的儿子
        List<Task> children = task.getChildren();
        if (children != null && isPause) {
            for (Task child : children) {
                pauseTask(child, true);
            }
        }
        return task;
    }

    /**
     * 比较两个任务
     *
     * @param t1List 任务1
     * @param t2List 任务2
     * @return 比较结果
     */
    public List<Map<String, Object>> comparTask(List<Task> t1List, List<Task> t2List) {
        List<Map<String, Object>> list = new ArrayList<>();
        if (t1List == null && t2List != null) {
            for (Task task : t2List) {
                Map<String, Object> map = new HashMap<>();
                map.put("id", new int[]{0, task.getId()});
                map.put("name", new String[]{null, task.getName()});
                map.put("startDate", new String[]{null, DateUtil.INS.parse(task.getStartDate())});
                map.put("endDate", new String[]{null, DateUtil.INS.parse(task.getEndDate())});
                map.put("verifierName", new String[]{null, task.getVerifier().getRealName()});
                map.put("children", comparTask(null, task.getChildren()));
                if (task.getChildren() == null) {
                    map.put("leaf", true);
                }
                map.put("iconCls", "");
                list.add(map);
            }
        }
        if (t2List == null && t1List != null) {
            for (Task task : t1List) {
                Map<String, Object> map = new HashMap<>();
                map.put("id", new int[]{task.getId(), 0});
                map.put("name", new String[]{task.getName(), null});
                map.put("startDate", new String[]{DateUtil.INS.parse(task.getStartDate()), null});
                map.put("endDate", new String[]{DateUtil.INS.parse(task.getEndDate()), null});
                map.put("verifierName", new String[]{task.getVerifier().getRealName(), null});
                map.put("children", comparTask(task.getChildren(), null));
                if (task.getChildren() == null) {
                    map.put("leaf", true);
                }
                map.put("iconCls", "");
                list.add(map);
            }
        }
        if (t1List == null && t2List == null) {
            return null;
        }
        if (t1List != null && t2List != null) {
            boolean isT1Big = t1List.size() >= t2List.size();
            List<Task> bigOne = isT1Big ? t1List : t2List;
            List<Task> samllOne = isT1Big ? t2List : t1List;
            for (int i = 0; i < bigOne.size(); i++) {
                Task big = bigOne.get(i);
                Task samll = null;
                if (samllOne.size() >= (i + 1)) {
                    samll = samllOne.get(i);
                }
                Task t1;
                Task t2;
                if (isT1Big) {
                    t1 = big;
                    t2 = samll;
                } else {
                    t1 = samll;
                    t2 = big;
                }
                Map<String, Object> map = new HashMap<>();
                map.put("id", new int[]{t1 == null ? 0 : t1.getId(), t2 == null ? 0 : t2.getId()});
                map.put("name", new String[]{t1 == null ? "" : t1.getName(), t2 == null ? "" : t2.getName()});
                map.put("startDate", new String[]{t1 == null ? "" : DateUtil.INS.parse(t1.getStartDate()), t2 == null ? "" : DateUtil.INS.parse(t2.getStartDate())});
                map.put("endDate", new String[]{t1 == null ? "" : DateUtil.INS.parse(t1.getEndDate()), t2 == null ? "" : DateUtil.INS.parse(t2.getEndDate())});
                map.put("verifierName", new String[]{t1 == null ? "" : t1.getVerifier().getRealName(), t2 == null ? "" : t2.getVerifier().getRealName()});
                map.put("children", comparTask(t1 == null ? null : t1.getChildren(), t2 == null ? null : t2.getChildren()));
                map.put("iconCls", "");
                if ((t1 == null || t1.getChildren() == null || t1.getChildren().size() == 0) || (t2 == null || t2.getChildren() == null || t2.getChildren().size() == 0)) {
                    map.put("leaf", true);
                } else {
                    map.put("leaf", false);
                    map.put("expanded", true);
                }
                list.add(map);
            }

        }
        return list;
    }

    /**
     * 通过项目和任务类型获取任务列表
     *
     * @param project      项目对象
     * @param taskTypeEnum 任务类型
     * @return 项目列表
     */
    public List<Task> getByProjectAndType(Project project, TaskTypeEnum taskTypeEnum) {
        return taskDao.findByProjectAndType(project, taskTypeEnum);
    }
}
